home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / kvikkalkul / kvik / src / kvikrt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-21  |  7.6 KB  |  428 lines  |  [TEXT/MPS ]

  1. /** kvikrt.c
  2.  ** Kvik runtime routines.
  3.  **
  4.  ** Written by and Copyright 1994 Asher Hoskins.
  5.  **
  6.  ** The author retains copyright on this implementation. Permission for
  7.  ** educational and non-profit use is granted to all. If you're planning to
  8.  ** make money with this or any code derived from it, check with the author
  9.  ** first.
  10.  **/
  11.  
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include "systypes.h"
  15. #include "systimeb.h"
  16. #include "timea.h"
  17. #include "kvikmath.h"
  18. #include "kvik_obj_types.h"
  19. #include "kvikrt.h"
  20. #include "parse.h"
  21.  
  22. static void check_dp(dp_t *);
  23. void output_baudot(kviknum);
  24. kviknum input_baudot(void);
  25. static int pwr2(int);
  26. static kviknum kviktime(void);
  27. extern data_area_t *data;
  28.  
  29. /** Allocate storage space. Returns a pointer to that storage.
  30.  **/
  31.  
  32. kviknum *alloc_storage(unsigned int id, unsigned int size, int value)
  33. {
  34.     data_area_t *dt;
  35.     kviknum *new_st;
  36.     data_area_t *new_dt;
  37.     unsigned int i;
  38.  
  39.     if (size == 0) {
  40.         printf("KVIK: TRIED TO CREATE ZERO LENGTH STORAGE %d\n", id);
  41.         exit(1);
  42.     }
  43.  
  44.     dt = data;
  45.     while (dt != NULL && dt->id != id)
  46.         dt = dt->next;
  47.  
  48.     if (dt != NULL) {
  49.         free(dt->start);
  50.         new_dt = dt;
  51.     }
  52.     else {
  53.         if ((new_dt = (data_area_t *) malloc(sizeof(data_area_t))) == NULL) {
  54.             printf("KVIK: CANNOT CREATE STORAGE %d\n", id);
  55.             exit(1);
  56.         }
  57.         new_dt->next = data;
  58.         data = new_dt;
  59.     }
  60.  
  61.     if ((new_st = (kviknum *) malloc(sizeof(kviknum)*size)) == NULL) {
  62.         printf("KVIK: CANNOT CREATE STORAGE %d TO SIZE %d\n", id, size);
  63.         exit(1);
  64.     }
  65.  
  66.     new_dt->id = id;
  67.     new_dt->start = new_st;
  68.     new_dt->size = size;
  69.  
  70.     for (i=0; i<size; i++)
  71.         new_st[i] = value;
  72.  
  73.     return(new_st);
  74. }
  75.  
  76. /** Set a data pointer to a data area. Bit of a bodge with the linked list
  77.  ** being searched twice - this was the easiest (ie. least thought :-)) way
  78.  ** of adding set_dp_intoff when I realised I needed it (for std call 888).
  79.  ** This will be fixed in a later release...
  80.  **/
  81.  
  82. void set_dp(dp_t *d, unsigned int id, kviknum pos)
  83. {
  84.     data_area_t *dt;
  85.     unsigned int offst;
  86.  
  87.     dt = data;
  88.     while (dt != NULL && dt->id != id)
  89.         dt = dt->next;
  90.  
  91.     if (dt == NULL) {
  92.         printf("KVIK: NO SUCH STORAGE %d\n", id);
  93.         exit(1);
  94.     }
  95.  
  96.     offst = kvik2doub(pos) * pwr2(dt->size);
  97.     set_dp_intoff(d, id, offst);
  98. }
  99.  
  100. /** Set a data pointer to a data area with an integer offset within the
  101.  ** area.
  102.  **/
  103.  
  104. void set_dp_intoff(dp_t *d, unsigned int id, unsigned int offst)
  105. {
  106.     data_area_t *dt;
  107.  
  108.     dt = data;
  109.     while (dt != NULL && dt->id != id)
  110.         dt = dt->next;
  111.  
  112.     if (dt == NULL) {
  113.         printf("KVIK: NO SUCH STORAGE %d\n", id);
  114.         exit(1);
  115.     }
  116.  
  117.     if (offst < 0 || offst >= dt->size) {
  118.         puts("KVIK: ILLEGAL STORAGE POSITION");
  119.         exit(1);
  120.     }
  121.  
  122.     d->id = id;
  123.     d->start = dt->start;
  124.     d->offset = offst;
  125.     d->size = dt->size;
  126. }
  127.  
  128. /** Return the power of 2 greater than 'n'.
  129.  **/
  130.  
  131. static int pwr2(int n)
  132. {
  133.     unsigned int p = 1;
  134.  
  135.     while (p < n)
  136.         p <<= 1;
  137.  
  138.     return(p);
  139. }
  140.  
  141. /** Check a data pointer is valid. Exit if it isn't.
  142.  **/
  143.  
  144. static void check_dp(dp_t *d)
  145. {
  146.     if (d->start == NULL) {
  147.         puts("KVIK: DATA POINTER NOT INITIALISED");
  148.         exit(1);
  149.     }
  150. }
  151.  
  152. /** Move data pointer back one location in a storage area.
  153.  **/
  154.  
  155. void previous(dp_t *d)
  156. {
  157.     check_dp(d);
  158.  
  159.     if (d->offset == 0) {
  160.         puts("KVIK: MOVED DATA POINTER OFF BEGINNING OF STORAGE");
  161.         exit(1);
  162.     }
  163.  
  164.     (d->offset)--;
  165. }
  166.  
  167. /** Move data pointer forwards one location in a storage area.
  168.  **/
  169.  
  170. void next(dp_t *d)
  171. {
  172.     check_dp(d);
  173.  
  174.     if (d->offset == d->size-1) {
  175.         puts("KVIK: MOVED DATA POINTER OFF END OF STORAGE");
  176.         exit(1);
  177.     }
  178.  
  179.     (d->offset)++;
  180. }
  181.  
  182. /** Read a data item from storage.
  183.  **/
  184.  
  185. kviknum read_data(dp_t *d)
  186. {
  187.     check_dp(d);
  188.  
  189.     return(*(d->start + d->offset));
  190. }
  191.  
  192. /** Write a data item into storage.
  193.  **/
  194.  
  195. void write_data(dp_t *d, kviknum n)
  196. {
  197.     check_dp(d);
  198.  
  199.     *(d->start + d->offset) = n;
  200. }
  201.  
  202. /** Perform an expression.
  203.  ** (I know 'op' should really be of type 'token_t' but keeping it as an
  204.  ** int means I don't have to include 'parse.h' into the output code even
  205.  ** if the compiler gets really picky...)
  206.  **/
  207.  
  208. kviknum expr(int s1, kviknum n1, int op, int s2, kviknum n2)
  209. {
  210.     double d1, d2;
  211.     double r;
  212.  
  213.     if ((d1 == OVERFLOW || d2 == OVERFLOW) && op != T_EQUAL
  214.         && op != T_NOT_EQUAL)
  215.         return(OVERFLOW);
  216.  
  217.     if (s1 == -1)
  218.         n1 = negate(n1);
  219.     if (s2 == -1)
  220.         n2 = negate(n2);
  221.  
  222.     d1 = kvik2doub(n1);
  223.     d2 = kvik2doub(n2);
  224.  
  225.     switch (op) {
  226.     case T_PLUS:
  227.         r = d1 + d2;
  228.         break;
  229.     case T_MINUS:
  230.         r = d1 - d2;
  231.         break;
  232.     case T_MULTIPLY:
  233.         r = d1 * d2;
  234.         break;
  235.     case T_DIVIDE:
  236.         r = d1 / d2;
  237.         break;
  238.     case T_EQUAL:
  239.         r = (d1 == d2) / 10.0;
  240.         break;
  241.     case T_NOT_EQUAL:
  242.         r = (d1 != d2) / 10.0;
  243.         break;
  244.     case T_LESS_THAN:
  245.         r = (d1 < d2) / 10.0;
  246.         break;
  247.     case T_GREATER_THAN:
  248.         r = (d1 > d2) / 10.0;
  249.         break;
  250.     case T_LESS_THAN_OR_EQ:
  251.         r = (d1 <= d2) / 10.0;
  252.         break;
  253.     case T_GREATER_THAN_OR_EQ:
  254.         r = (d1 >= d2) / 10.0;
  255.     }
  256.  
  257.     return(doub2kvik(r));
  258. }
  259.  
  260. /** Read a value from a channel.
  261.  **/
  262.  
  263. kviknum read_channel(int c)
  264. {
  265.     switch(c) {
  266.  
  267.     case 0:
  268.         return(input_baudot());
  269.  
  270.     case 1:
  271.         return(doub2kvik(-0.1));
  272.  
  273.     case 2:
  274.         return(kviktime());
  275.  
  276.     case 3:
  277.         return(OVERFLOW);        /* Hot simulation :-) */
  278.  
  279.     default:
  280.         return(doub2kvik(-0.1));
  281.     }
  282. }
  283.  
  284. /** Write a value to a channel.
  285.  **/
  286.  
  287. void write_channel(int c, kviknum n)
  288. {
  289.     switch(c) {
  290.  
  291.     case 0:
  292.         output_baudot(n);
  293.         break;
  294.  
  295.     case 9:                            /* FOR TESTING ONLY */
  296.         printf("Chan9: ");
  297.         if (n == OVERFLOW)
  298.             printf("Overflow\n");
  299.         else
  300.             printf("%.5lf\n", kvik2doub(n));
  301.         break;
  302.  
  303.     default:
  304.         ;
  305.     }
  306. }
  307.  
  308. /** Output a Baudot code character.
  309.  **/
  310.  
  311. void output_baudot(kviknum n)
  312. {
  313.     static int baudot_shift = 0;
  314.     static char baudot_chrs[] =
  315.         "bTrO HNMdLRGIPCVEZDBSYFXAWJfUQKlb5r9 n,.d)4n80:=3+w?!6n/-2cf71(l";
  316.     int chr;
  317.     char bc;
  318.  
  319.     chr = 32 * kvik2doub(n);
  320.     if (chr < 0 || chr > 31)
  321.         return;
  322.  
  323.     bc = baudot_chrs[baudot_shift + chr];
  324.     switch(bc) {
  325.     case 'w': case 'n': case 'b':    /* who are you, nothing, blank */
  326.         break;    /* do nothing */
  327.     case 'c':                        /* bell */
  328.         putchar('\a');
  329.         break;
  330.     case 'l':                        /* letter shift */
  331.         baudot_shift = 0;
  332.         break;
  333.     case 'f':                        /* figure shift */
  334.         baudot_shift = 32;
  335.         break;
  336.     case 'r':                        /* carriage return */
  337.         putchar('\r');
  338.         break;
  339.     case 'd':                        /* line feed */
  340.         putchar('\n');
  341.         break;
  342.     default:                        /* everything else */
  343.         putchar(bc);
  344.     }
  345.  
  346.     return;
  347. }
  348.  
  349. /** Input a character from the keyboard. Sends letter/figure shifts
  350.  ** automatically.
  351.  **
  352.  ** Returns a negative value on EOF.
  353.  **/
  354.  
  355. kviknum input_baudot(void)
  356. {
  357.     static int baudot_shift = 0;
  358.     static int chr_buffer = -1;
  359.     static char baudot_chrs[] =
  360.         "bTrO HNMdLRGIPCVEZDBSYFXAWJfUQKlb5r9 n,.d)4n80:=3+w?!6n/-2cf71(l";
  361.     int chr, i, cdiff;
  362.  
  363.     if (chr_buffer != -1) {
  364.         chr = chr_buffer;
  365.         chr_buffer = -1;
  366.         return(doub2kvik(chr/32.0));
  367.     }
  368.  
  369.     if ((chr = getchar()) == EOF)
  370.         return(doub2kvik(-0.1));
  371.  
  372.     if (islower(chr))
  373.         chr = toupper(chr);
  374.  
  375.     switch (chr) {
  376.     case ' ':
  377.         return(doub2kvik(0.12500));
  378.     case '\a':
  379.         chr = 'c';
  380.         break;
  381.     case '\r':
  382.         return(doub2kvik(0.06250));
  383.     case '\n':
  384.         return(doub2kvik(0.25000));
  385.     }
  386.  
  387.     for (i = 0; i < 63; i++)
  388.         if (chr == baudot_chrs[i]) {
  389.             cdiff = i - baudot_shift;
  390.             if (cdiff < 0) {
  391.                 baudot_shift = 0;            /* set letter mode */
  392.                 chr_buffer = i;
  393.                 return(doub2kvik(0.96875));
  394.             }
  395.             if (cdiff > 31) {
  396.                 baudot_shift = 32;            /* set figure mode */
  397.                 chr_buffer = i - 32;
  398.                 return(doub2kvik(0.84375));
  399.             }
  400.             return(doub2kvik(cdiff/32.0));
  401.         }
  402.  
  403.     return(doub2kvik(0.0));        /* return blank if non-Baudot chr entered */
  404. }
  405.  
  406. /** Return position within hour as number from "0 to "9.
  407.  ** Note that if the precision of arithmetic is ever increased then
  408.  ** the [-]0.99995's will have to be changed.
  409.  **/
  410.  
  411. static kviknum kviktime(void)
  412. {
  413.     time_t t;
  414.     struct tm *lt;
  415.     double convtime;
  416.  
  417.     t = time(NULL);
  418.     lt = localtime(&t);
  419.  
  420.     convtime = (lt->tm_min*60 + lt->tm_sec)/1800.0 - 1.0;
  421.     if (convtime < -0.99995)
  422.         convtime = -0.99995;
  423.     if (convtime > 0.99995)
  424.         convtime = 0.99995;
  425.  
  426.     return(doub2kvik(convtime));
  427. }
  428.